/*
  Copyright (C) 2011 Zhao Ming(zhao.ming29@gmail.com)

  All rights reserved.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License version 2.1, as
  published by the Free Software Foundation.  This program is
  distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "Rcosfir.h"
#include "DownInterp.h"
#include "AWGN.h"
#include "Carrier.h"
#include "LogFile.h"
#include "Noise.h"

#include <LRCTransmiter.h>
#include <LRCReceiver.h>
#include <GHGS.h>

#include <math.h>
#include <stdio.h>

const double ChipRate = 27./12.*1e6;
const double SampleRate = ChipRate * 4;
const double ReceiverSampleRate = SampleRate/2.;
const double CarrierOffset = 0;
const int NCOWIDTH = 24;
const int Amplitude = 64;
const int frameLen = 128+640*2;
const int simLen = 4500000;
const int overhead = 128;

struct Message Rmessage[MAXMES];

struct system {
	CRcosfir *Tfir;
	CRcosfir *RfirI;
	CRcosfir *RfirQ;
	CDownInterp *Down;
	CCarrier *freqOff;
	CLRCTransmiter *aT;
	CLRCReceiver *aR;
	CNoise *rand;
};

	
int genFrame( int *buf, char *tbuf, int *mes, int Amp, double FreqOff, struct system& sys )
{
		double rate = FreqOff*ChipRate*12/SampleRate;
		int nco=(1<<NCOWIDTH);
		rate*=(double)nco;
		sys.freqOff->setfreq(rate);
		sys.freqOff->setph(sys.rand->Union()); 
		rate = FreqOff*ReceiverSampleRate/SampleRate;
		rate*=(double)nco;
		sys.Down->setfreq(-rate);
		sys.Down->setph(sys.rand->Union()); 
		
		sys.aT->send(tbuf,	mes, 2);
		int tfir,tr,ti,rfirr,rfiri,dr,di;
		int bitCounter = 0;
		int recvCounter = 0;
		for( int chipCounter=0;chipCounter<(frameLen+overhead)*4;chipCounter++ )
		{
			if( (chipCounter&3)==0 )
			{
				int c = tbuf[bitCounter/8]>>(bitCounter%8);
				c&=1;
				c=Amp*(1-2*c);
				sys.Tfir->cei( c, tfir );
				bitCounter++;
			}
			else
				sys.Tfir->cei( 0, tfir );
			sys.freqOff->cei(tfir, 0, tr, ti);
			sys.RfirI->cei( tr, rfirr );
			sys.RfirQ->cei( ti, rfiri );
			if( sys.Down->cei( rfirr,rfiri, dr, di )==1 )
			{
				buf[recvCounter*2]=dr;
				buf[recvCounter*2+1]=di;
				recvCounter++;
			}
		}
		return recvCounter;
}

char limit( int a )
{
	char c=a;
	if( a>127 )
		c=127;
	if( a<-127 )
		c=-127;
	return c;	
}

int main( int argc, char *argv[] )
{
	struct system aSys;
		
	int *rbuf = new int[frameLen*8];
	int *buf = new int[frameLen*8];
	char *crbuf = new char[512*4];
	char *tbuf = new char[(frameLen+overhead)/8];

	double active;
	sscanf( argv[1],"%lf",&active );
	active/=ReceiverSampleRate;
	int TH;
	sscanf( argv[2],"%d",&TH );
	
	aSys.Tfir = new CRcosfir();
	aSys.RfirI = new CRcosfir();
	aSys.RfirQ = new CRcosfir();
	
	double rate=1.-ReceiverSampleRate/SampleRate;
	int nco=(1<<NCOWIDTH);
	rate*=(double)nco;
	aSys.Down = new CDownInterp( (int)rate, NCOWIDTH, 8 );
	rate = CarrierOffset*(double)nco/SampleRate;
	
	aSys.freqOff = new CCarrier( (int)rate, NCOWIDTH );
	aSys.aT = new CLRCTransmiter(1,1,2);
	aSys.aR = new CLRCReceiver( 1,1,2,TH );

	LogFile *log = new LogFile();
	log->setrec( 1, "work/RecvData.log" );
	aSys.rand = new CNoise();

	int i,j,k;
	int recvCounter=0,crCounter=0;
	int message = 0;
	int lastTime = 0;
	int lasti = 0;
	for( i=0;i<simLen;i++ )
	{
		if( aSys.rand->Union()<active )
		{
			int mes[2] = { message&0x3ff, message>>10 };
			double a = aSys.rand->Union();
			a-=0.5;
			a*=2.;
			int Amp = (double)Amplitude*pow(10.,a/20.);
			a = aSys.rand->Union();
			a-=0.5;
			a*=100.;
			double FreqOff = a/1.e6;
			int len = genFrame(buf,tbuf,mes,Amp,FreqOff,aSys);
			message++; 
			int sampleA=0,sampleB;
			for( sampleB=recvCounter*2;sampleB<frameLen*8;sampleB++ )
			{
				rbuf[sampleB]+=buf[sampleA];
				sampleA++;
				if( sampleA==len*2 )
					break;
			} 
			for( sampleB=0;sampleA<len*2;sampleA++ )
			{
				rbuf[sampleB]+=buf[sampleA];
				sampleB++;
			}
			printf("send %d[%d] with Amp %d FreqOff %lf %d[%d]\n",message,len,Amp,FreqOff,i,i-lasti);
			lasti = i;
			
		}
		crbuf[crCounter]=limit(rbuf[recvCounter*2]);
		crCounter++;
		crbuf[crCounter]=limit(rbuf[recvCounter*2+1]);
		crCounter++;
		log->rec(crbuf[crCounter-2],crbuf[crCounter-1],1);
		rbuf[recvCounter*2]=0;
		rbuf[recvCounter*2+1]=0;
		if( crCounter==4*512 )
		{
			crCounter = 0;
			int num = aSys.aR->recv( crbuf, 512*4, Rmessage );
			for( j=0;j<num;j++ )
			{
				for( k=0;k<Rmessage[j].len;k++ )
					printf("%d ",Rmessage[j].mes[k]);
				printf(" [%d]\n",Rmessage[j].time-lastTime);
				lastTime = Rmessage[j].time;	
			}
		}	
		recvCounter++;
		if( recvCounter==4*frameLen )
		{
			recvCounter = 0;
		}
	}
	delete buf;
	delete rbuf;
	delete tbuf;
	delete crbuf;
	delete aSys.Tfir;
	delete aSys.RfirI;
	delete aSys.RfirQ;
	delete aSys.Down;
	delete aSys.freqOff;
	delete aSys.aT;
	delete aSys.aR;
	delete aSys.rand;
	delete log;
	return 0;
}
